home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 2 / Amiga Tools 2.iso / tools / vim / src / buffer.c < prev    next >
C/C++ Source or Header  |  1995-03-09  |  22KB  |  1,019 lines

  1. /* vi:ts=4:sw=4
  2.  *
  3.  * VIM - Vi IMproved        by Bram Moolenaar
  4.  *
  5.  * Read the file "credits.txt" for a list of people who contributed.
  6.  * Read the file "uganda.txt" for copying and usage conditions.
  7.  */
  8.  
  9. /*
  10.  * buffer.c: functions for dealing with the buffer structure
  11.  */
  12.  
  13. /*
  14.  * The buffer list is a double linked list of all buffers.
  15.  * Each buffer can be in one of these states:
  16.  * never loaded: b_neverloaded == TRUE, only the file name is valid
  17.  *   not loaded: b_ml.ml_mfp == NULL, no memfile allocated
  18.  *       hidden: b_nwindows == 0, loaded but not displayed in a window
  19.  *       normal: loaded and displayed in a window
  20.  *
  21.  * Instead of storing file names all over the place, each file name is
  22.  * stored in the buffer list. It can be referenced by a number.
  23.  *
  24.  * The current implementation remembers all file names ever used.
  25.  */
  26.  
  27. #include "vim.h"
  28. #include "globals.h"
  29. #include "proto.h"
  30. #include "param.h"
  31.  
  32. static void        enter_buffer __ARGS((BUF *));
  33. static BUF        *buflist_findname __ARGS((char_u *));
  34. static BUF        *buflist_findnr __ARGS((int));
  35. static void        buflist_setlnum __ARGS((BUF *, linenr_t));
  36. static linenr_t buflist_findlnum __ARGS((BUF *));
  37.  
  38. /*
  39.  * Open current buffer, that is: open the memfile and read the file into memory
  40.  * return FAIL for failure, OK otherwise
  41.  */
  42.      int
  43. open_buffer()
  44. {
  45.     if (readonlymode && curbuf->b_filename != NULL)
  46.         curbuf->b_p_ro = TRUE;
  47.     if (ml_open() == FAIL)
  48.     {
  49.         /*
  50.          * There MUST be a memfile, otherwise we can't do anything
  51.          * If we can't create one for the current buffer, take another buffer
  52.          */
  53.         close_buffer(curbuf, FALSE, FALSE);
  54.         for (curbuf = firstbuf; curbuf != NULL; curbuf = curbuf->b_next)
  55.             if (curbuf->b_ml.ml_mfp != NULL)
  56.                 break;
  57.         /*
  58.          * if there is no memfile at all, exit
  59.          * This is OK, since there are no changes to loose.
  60.          */
  61.         if (curbuf == NULL)
  62.         {
  63.             EMSG("Cannot allocate buffer, exiting...");
  64.             getout(2);
  65.         }
  66.         EMSG("Cannot allocate buffer, using other one...");
  67.         enter_buffer(curbuf);
  68.         return FAIL;
  69.     }
  70.     if (curbuf->b_filename != NULL)
  71.     {
  72.         if (readfile(curbuf->b_filename, curbuf->b_sfilename, (linenr_t)0,
  73.                                         TRUE, (linenr_t)0, MAXLNUM) == FAIL)
  74.             return FAIL;
  75.     }
  76.     else
  77.         MSG("Empty Buffer");
  78.     UNCHANGED(curbuf);
  79.     curbuf->b_neverloaded = FALSE;
  80.     return OK;
  81. }
  82.  
  83. /*
  84.  * Close the link to a buffer. If "free_buf" is TRUE free the buffer if it
  85.  * becomes unreferenced. The caller should get a new buffer very soon!
  86.  * if 'remove' is TRUE, remove the buffer from the buffer list.
  87.  */
  88.     void
  89. close_buffer(buf, free_buf, remove)
  90.     BUF        *buf;
  91.     int        free_buf;
  92.     int        remove;
  93. {
  94.     if (buf->b_nwindows > 0)
  95.         --buf->b_nwindows;
  96.     if (buf->b_nwindows > 0 || !free_buf)
  97.     {
  98.         if (buf == curbuf)
  99.             u_sync();        /* sync undo before going to another buffer */
  100.         return;
  101.     }
  102.  
  103.     buf_freeall(buf);        /* free all things allocated for this buffer */
  104.     /*
  105.      * If there is no file name, remove the buffer from the list
  106.      */
  107.     if (buf->b_filename == NULL || remove)
  108.     {
  109.         free(buf->b_filename);
  110.         free(buf->b_sfilename);
  111.         if (buf->b_prev == NULL)
  112.             firstbuf = buf->b_next;
  113.         else
  114.             buf->b_prev->b_next = buf->b_next;
  115.         if (buf->b_next == NULL)
  116.             lastbuf = buf->b_prev;
  117.         else
  118.             buf->b_next->b_prev = buf->b_prev;
  119.         free(buf);
  120.     }
  121.     else
  122.         buf_clear(buf);
  123. }
  124.  
  125. /*
  126.  * buf_clear() - make buffer empty
  127.  */
  128.     void
  129. buf_clear(buf)
  130.     BUF        *buf;
  131. {
  132.     buf->b_ml.ml_line_count = 1;
  133.     buf->b_changed = FALSE;
  134. #ifndef MSDOS
  135.     buf->b_shortname = FALSE;
  136. #endif
  137.     buf->b_p_eol = TRUE;
  138.     buf->b_ml.ml_mfp = NULL;
  139.     buf->b_ml.ml_flags = ML_EMPTY;                    /* empty buffer */
  140. }
  141.  
  142. /*
  143.  * buf_freeall() - free all things allocated for the buffer
  144.  */
  145.     void
  146. buf_freeall(buf)
  147.     BUF        *buf;
  148. {
  149.     u_blockfree(buf);                /* free the memory allocated for undo */
  150.     ml_close(buf);                    /* close and delete the memline/memfile */
  151.     buf->b_ml.ml_line_count = 0;    /* no lines in buffer */
  152.     u_clearall(buf);                /* reset all undo information */
  153. }
  154.  
  155. /*
  156.  * Implementation of the command for the buffer list
  157.  */
  158.     int
  159. do_buffer(action, start, dir, count, forceit)
  160.     int        action;        /* 0 = normal, 1 = split window, 2 = unload, 3 = delete */
  161.     int        start;        /* 0 = current, 1 = first, 2 = last, 3 = modified */
  162.     int        dir;        /* FORWARD or BACKWARD */
  163.     int        count;        /* buffer number or number of buffers */
  164.     int        forceit;    /* TRUE for :bdelete! */
  165. {
  166.     BUF        *buf;
  167.     int        retval;
  168.  
  169.     switch (start)
  170.     {
  171.     case 0: buf = curbuf;
  172.             break;
  173.     case 1: buf = firstbuf;
  174.             break;
  175.     case 2: buf = curbuf;
  176.             while (buf->b_next != NULL)
  177.                 buf = buf->b_next;
  178.             break;
  179.     default: buf = curbuf;
  180.             break;
  181.     }
  182.     if (start == 3)            /* find next modified buffer */
  183.     {
  184.         while (count-- > 0)
  185.         {
  186.             do
  187.             {
  188.                 buf = buf->b_next;
  189.                 if (buf == NULL)
  190.                     buf = firstbuf;
  191.             }
  192.             while (buf != curbuf && !buf->b_changed);
  193.         }
  194.         if (!buf->b_changed)
  195.         {
  196.             EMSG("No modified buffer found");
  197.             return FAIL;
  198.         }
  199.     }
  200.     else if (start == 1 && count)        /* find specified buffer number */
  201.     {
  202.         while (buf != NULL && buf->b_fnum != count)
  203.             buf = buf->b_next;
  204.     }
  205.     else
  206.     {
  207.         while (buf != NULL && count-- > 0)
  208.         {
  209.             if (dir == FORWARD)
  210.                 buf = buf->b_next;
  211.             else
  212.                 buf = buf->b_prev;
  213.         }
  214.     }
  215.     if (buf == NULL)        /* could not find it */
  216.     {
  217.         if (start == 1)
  218.             EMSG2("Cannot go to buffer %ld", (char_u *)count);
  219.         else if (dir == FORWARD)
  220.             EMSG("Cannot go beyond last buffer");
  221.         else
  222.             EMSG("Cannot go before first buffer");
  223.         return FAIL;
  224.     }
  225.     /*
  226.      * delete buffer buf from memory and/or the list
  227.      */
  228.     if (action == 2 || action == 3)
  229.     {
  230.         if (buf->b_nwindows > 1 || (buf != curbuf && buf->b_nwindows != 0))
  231.         {
  232.             EMSG2("Other window editing buffer %ld", (char_u *)buf->b_fnum);
  233.             return FAIL;
  234.         }
  235.         if (!forceit && buf->b_changed)
  236.         {
  237.             EMSG2("No write since last change for buffer %ld (use ! to override)",
  238.                         (char_u *)buf->b_fnum);
  239.             return FAIL;
  240.         }
  241.         /*
  242.          * if deleting last buffer, make it empty
  243.          */
  244.         if (firstbuf->b_next == NULL)
  245.         {
  246.             buf = curbuf;
  247.             retval = doecmd(NULL, NULL, NULL, FALSE, (linenr_t)1);
  248.                 /* the doecmd() may create a new buffer, then we have to
  249.                  * delete the old one */
  250.             if (action == 3 && buf != curbuf)
  251.                 close_buffer(buf, TRUE, action == 3);
  252.             return retval;
  253.         }
  254.         /*
  255.          * If deleted buffer is not current one, delete it here.
  256.          * Otherwise find buffer to go to and delete it below.
  257.          */
  258.         {
  259.             if (buf != curbuf)
  260.             {
  261.                 close_buffer(buf, TRUE, action == 3);
  262.                 return OK;
  263.             }
  264.             if (buf->b_next != NULL)
  265.                 buf = buf->b_next;
  266.             else
  267.                 buf = buf->b_prev;
  268.         }
  269.     }
  270. /*
  271.  * make buf current buffer
  272.  */
  273.     if (action == 1)        /* split window first */
  274.     {
  275.         if (win_split(0L, FALSE) == FAIL)
  276.             return FAIL;
  277.     }
  278.     buflist_altlnum();        /* remember curpos.lnum */
  279.     close_buffer(curbuf, action == 2 || action == 3, action == 3);
  280.     enter_buffer(buf);
  281.     return OK;
  282. }
  283.  
  284. /*
  285.  * enter a new current buffer.
  286.  * (old curbuf must have been freed already)
  287.  */
  288.     static void
  289. enter_buffer(buf)
  290.     BUF        *buf;
  291. {
  292.     int        need_fileinfo = TRUE;
  293.  
  294.     if (buf->b_neverloaded)
  295.     {
  296.         buf_copy_options(curbuf, buf);
  297.         buf->b_neverloaded = FALSE;
  298.     }
  299.     curwin->w_buffer = buf;
  300.     curbuf = buf;
  301.     ++curbuf->b_nwindows;
  302.     if (curbuf->b_ml.ml_mfp == NULL)    /* need to load the file */
  303.     {
  304.         open_buffer();
  305.         need_fileinfo = FALSE;
  306.     }
  307.     buflist_getlnum();                    /* restore curpos.lnum */
  308.     maketitle();
  309.     updateScreen(NOT_VALID);
  310.     if (need_fileinfo)
  311.         fileinfo(did_cd);
  312. }
  313.  
  314. /*
  315.  * functions for dealing with the buffer list
  316.  */
  317.  
  318. /*
  319.  * Add a file name to the buffer list. Return a pointer to the buffer.
  320.  * If the same file name already exists return a pointer to that buffer.
  321.  * If it does not exist, or if fname == NULL, a new entry is created.
  322.  * If use_curbuf is TRUE, may use current buffer.
  323.  * This is the ONLY way to create a new buffer.
  324.  */
  325.     BUF *
  326. buflist_new(fname, sfname, lnum, use_curbuf)
  327.     char_u        *fname;
  328.     char_u        *sfname;
  329.     linenr_t    lnum;
  330.     int            use_curbuf;
  331. {
  332.     static int    top_file_num = 1;            /* highest file number */
  333.     BUF            *buf;
  334.  
  335.     fname_expand(&fname, &sfname);
  336.  
  337. /*
  338.  * If file name already exists in the list, update the entry
  339.  */
  340.     if (fname != NULL && (buf = buflist_findname(fname)) != NULL)
  341.     {
  342.         if (lnum != 0)
  343.             buflist_setlnum(buf, lnum);
  344.         if (buf->b_neverloaded && curbuf != NULL && buf != curbuf)
  345.             buf_copy_options(curbuf, buf);
  346.         return buf;
  347.     }
  348.  
  349. /*
  350.  * If the current buffer has no name and no contents, use the current buffer.
  351.  * Otherwise: Need to allocate a new buffer structure.
  352.  *
  353.  * This is the ONLY place where a new buffer structure is allocated!
  354.  */
  355.     if (use_curbuf && curbuf != NULL && curbuf->b_filename == NULL &&
  356.                 curbuf->b_nwindows <= 1 &&
  357.                 (curbuf->b_ml.ml_mfp == NULL || curbuf->b_ml.ml_flags == ML_EMPTY))
  358.         buf = curbuf;
  359.     else
  360.     {
  361.         buf = (BUF *)alloc((unsigned)sizeof(BUF));
  362.         if (buf == NULL)
  363.             return NULL;
  364.         memset((char *)buf, 0, sizeof(BUF));
  365.     }
  366.  
  367.     if (fname != NULL)
  368.     {
  369.         buf->b_filename = strsave(fname);
  370.         buf->b_sfilename = strsave(sfname);
  371.     }
  372.     if (buf->b_winlnum == NULL)
  373.         buf->b_winlnum = (WINLNUM *)alloc((unsigned)sizeof(WINLNUM));
  374.     if ((fname != NULL && (buf->b_filename == NULL || buf->b_sfilename == NULL)) ||
  375.                                 buf->b_winlnum == NULL)
  376.     {
  377.         free(buf->b_filename);
  378.         buf->b_filename = NULL;
  379.         free(buf->b_sfilename);
  380.         buf->b_sfilename = NULL;
  381.         if (buf != curbuf)
  382.         {
  383.             free(buf->b_winlnum);
  384.             free(buf);
  385.         }
  386.         return NULL;
  387.     }
  388.  
  389.     if (buf == curbuf)
  390.     {
  391.         buf_freeall(buf);        /* free all things allocated for this buffer */
  392.         buf->b_nwindows = 0;
  393.     }
  394.     else
  395.     {
  396.         if (curbuf != NULL)        /* don't do this for first buffer */
  397.             buf_copy_options(curbuf, buf);
  398.     
  399.         /*
  400.          * put new buffer at the end of the buffer list
  401.          */
  402.         buf->b_next = NULL;
  403.         if (firstbuf == NULL)            /* buffer list is empty */
  404.         {
  405.             buf->b_prev = NULL;
  406.             firstbuf = buf;
  407.         }
  408.         else                            /* append new buffer at end of the list */
  409.         {
  410.             lastbuf->b_next = buf;
  411.             buf->b_prev = lastbuf;
  412.         }
  413.         lastbuf = buf;
  414.  
  415.         buf->b_fnum = top_file_num++;
  416.         if (top_file_num < 0)            /* wrap around (may cause duplicates) */
  417.         {
  418.             EMSG("Warning: List of file names overflow");
  419.             sleep(3);                    /* make sure it is noticed */
  420.             top_file_num = 1;
  421.         }
  422.  
  423.         buf->b_winlnum->wl_lnum = lnum;
  424.         buf->b_winlnum->wl_next = NULL;
  425.         buf->b_winlnum->wl_prev = NULL;
  426.         buf->b_winlnum->wl_win = curwin;
  427.     }
  428.  
  429.     if (did_cd)
  430.         buf->b_xfilename = buf->b_filename;
  431.     else
  432.         buf->b_xfilename = buf->b_sfilename;
  433.     buf->b_u_synced = TRUE;
  434.     buf->b_neverloaded = TRUE;
  435.     buf_clear(buf);
  436.     clrallmarks(buf);                /* clear marks */
  437.  
  438.     return buf;
  439. }
  440.  
  441. /*
  442.  * get alternate file n
  443.  * set linenr to lnum or altlnum if lnum == 0
  444.  * if (setpm) setpcmark
  445.  * return FAIL for failure, OK for success
  446.  */
  447.     int
  448. buflist_getfile(n, lnum, setpm)
  449.     int            n;
  450.     linenr_t    lnum;
  451.     int            setpm;
  452. {
  453.     BUF        *buf;
  454.  
  455.     buf = buflist_findnr(n);
  456.     if (buf == NULL)
  457.     {
  458.         emsg(e_noalt);
  459.         return FAIL;
  460.     }
  461.     if (lnum == 0)
  462.         lnum = buflist_findlnum(buf);    /* altlnum may be changed by getfile() */
  463.     RedrawingDisabled = TRUE;
  464.     if (getfile(buf->b_filename, buf->b_sfilename, setpm, lnum) <= 0)
  465.     {
  466.         RedrawingDisabled = FALSE;
  467.         return OK;
  468.     }
  469.     RedrawingDisabled = FALSE;
  470.     return FAIL;
  471. }
  472.  
  473. /*
  474.  * go to the last know line number for the current buffer
  475.  */
  476.     void
  477. buflist_getlnum()
  478. {
  479.     linenr_t    lnum;
  480.  
  481.     curwin->w_cursor.lnum = 1;
  482.     curwin->w_cursor.col = 0;
  483.     lnum = buflist_findlnum(curbuf);
  484.     if (lnum != 0 && lnum <= curbuf->b_ml.ml_line_count)
  485.         curwin->w_cursor.lnum = lnum;
  486. }
  487.  
  488. /*
  489.  * find file in buffer list by name (it has to be for the current window)
  490.  * 'fname' must have a full path.
  491.  */
  492.     static BUF    *
  493. buflist_findname(fname)
  494.     char_u        *fname;
  495. {
  496.     BUF            *buf;
  497.  
  498.     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  499.         if (buf->b_filename != NULL && fnamecmp(fname, buf->b_filename) == 0)
  500.             return (buf);
  501.     return NULL;
  502. }
  503.  
  504. /*
  505.  * find file in buffer name list by number
  506.  */
  507.     static BUF    *
  508. buflist_findnr(nr)
  509.     int            nr;
  510. {
  511.     BUF            *buf;
  512.  
  513.     if (nr == 0)
  514.         nr = curwin->w_alt_fnum;
  515.     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  516.         if (buf->b_fnum == nr)
  517.             return (buf);
  518.     return NULL;
  519. }
  520.  
  521. /*
  522.  * get name of file 'n' in the buffer list
  523.  */
  524.      char_u *
  525. buflist_nr2name(n)
  526.     int n;
  527. {
  528.     BUF        *buf;
  529.     char_u    *fname;
  530.  
  531.     buf = buflist_findnr(n);
  532.     if (buf == NULL)
  533.         return NULL;
  534.     fname = did_cd ? buf->b_filename : buf->b_sfilename;
  535.     home_replace(fname, NameBuff, MAXPATHL);
  536.     return NameBuff;
  537. }
  538.  
  539. /*
  540.  * set the lnum for the buffer 'buf' and the current window
  541.  */
  542.     static void
  543. buflist_setlnum(buf, lnum)
  544.     BUF            *buf;
  545.     linenr_t    lnum;
  546. {
  547.     WINLNUM        *wlp;
  548.     
  549.     for (wlp = buf->b_winlnum; wlp != NULL; wlp = wlp->wl_next)
  550.         if (wlp->wl_win == curwin)
  551.             break;
  552.     if (wlp == NULL)            /* make new entry */
  553.     {
  554.         wlp = (WINLNUM *)alloc((unsigned)sizeof(WINLNUM));
  555.         if (wlp == NULL)
  556.             return;
  557.         wlp->wl_win = curwin;
  558.     }
  559.     else                        /* remove entry from list */
  560.     {
  561.         if (wlp->wl_prev)
  562.             wlp->wl_prev->wl_next = wlp->wl_next;
  563.         else
  564.             buf->b_winlnum = wlp->wl_next;
  565.         if (wlp->wl_next)
  566.             wlp->wl_next->wl_prev = wlp->wl_prev;
  567.     }
  568.     wlp->wl_lnum = lnum;
  569. /*
  570.  * insert entry in front of the list
  571.  */
  572.     wlp->wl_next = buf->b_winlnum;
  573.     buf->b_winlnum = wlp;
  574.     wlp->wl_prev = NULL;
  575.     if (wlp->wl_next)
  576.         wlp->wl_next->wl_prev = wlp;
  577.  
  578.     return;
  579. }
  580.  
  581. /*
  582.  * find the lnum for the buffer 'buf' for the current window
  583.  */
  584.     static linenr_t
  585. buflist_findlnum(buf)
  586.     BUF        *buf;
  587. {
  588.     WINLNUM     *wlp;
  589.  
  590.     for (wlp = buf->b_winlnum; wlp != NULL; wlp = wlp->wl_next)
  591.         if (wlp->wl_win == curwin)
  592.             break;
  593.  
  594.     if (wlp == NULL)        /* if no lnum for curwin, use the first in the list */
  595.         wlp = buf->b_winlnum;
  596.  
  597.     if (wlp)
  598.         return wlp->wl_lnum;
  599.     else
  600.         return (linenr_t)1;
  601. }
  602.  
  603. /*
  604.  * list all know file names (for :files and :buffers command)
  605.  */
  606.     void
  607. buflist_list()
  608. {
  609.     BUF            *buf;
  610.     int            len;
  611.  
  612.     gotocmdline(TRUE, NUL);
  613.     for (buf = firstbuf; buf != NULL && !got_int; buf = buf->b_next)
  614.     {
  615.         if (buf != firstbuf)
  616.             msg_outchar('\n');
  617.         if (buf->b_xfilename == NULL)
  618.             STRCPY(NameBuff, "No File");
  619.         else
  620.             /* careful: home_replace calls vimgetenv(), which uses IObuff! */
  621.             home_replace(buf->b_xfilename, NameBuff, MAXPATHL);
  622.  
  623.         sprintf((char *)IObuff, "%3d %c%c%c \"",
  624.                 buf->b_fnum,
  625.                 buf == curbuf ? '%' :
  626.                         (curwin->w_alt_fnum == buf->b_fnum ? '#' : ' '),
  627.                 buf->b_ml.ml_mfp == NULL ? '-' :
  628.                         (buf->b_nwindows == 0 ? 'h' : ' '),
  629.                 buf->b_changed ? '+' : ' ');
  630.  
  631.         len = STRLEN(IObuff);
  632.         STRNCPY(IObuff + len, NameBuff, (size_t)IOSIZE - 20 - len);
  633.  
  634.         len = STRLEN(IObuff);
  635.         IObuff[len++] = '"';
  636.         /*
  637.          * try to put the "line" strings in column 40
  638.          */
  639.         do
  640.         {
  641.             IObuff[len++] = ' ';
  642.         } while (len < 40 && len < IOSIZE - 18);
  643.         sprintf((char *)IObuff + len, "line %ld",
  644.                 buf == curbuf ? curwin->w_cursor.lnum :
  645.                                 (long)buflist_findlnum(buf));
  646.         msg_outstr(IObuff);
  647.         flushbuf();            /* output one line at a time */
  648.         breakcheck();
  649.     }
  650.     msg_end();
  651. }
  652.  
  653. /*
  654.  * get file name and line number for file 'fnum'
  655.  * used by DoOneCmd() for translating '%' and '#'
  656.  * return FAIL if not found, OK for success
  657.  */
  658.     int
  659. buflist_name_nr(fnum, fname, lnum)
  660.     int            fnum;
  661.     char_u        **fname;
  662.     linenr_t    *lnum;
  663. {
  664.     BUF            *buf;
  665.  
  666.     buf = buflist_findnr(fnum);
  667.     if (buf == NULL || buf->b_filename == NULL)
  668.         return FAIL;
  669.  
  670.     if (did_cd)
  671.         *fname = buf->b_filename;
  672.     else
  673.         *fname = buf->b_sfilename;
  674.     *lnum = buflist_findlnum(buf);
  675.  
  676.     return OK;
  677. }
  678.  
  679. /*
  680.  * Set the current file name to 's', short file name to 'ss'.
  681.  * The file name with the full path is also remembered, for when :cd is used.
  682.  * Returns FAIL for failure (file name already in use by other buffer)
  683.  *         OK otherwise.
  684.  */
  685.     int
  686. setfname(fname, sfname, message)
  687.     char_u *fname, *sfname;
  688.     int        message;
  689. {
  690.     BUF        *buf;
  691.  
  692.     if (fname == NULL || *fname == NUL)
  693.     {
  694.         curbuf->b_filename = NULL;
  695.         curbuf->b_sfilename = NULL;
  696.     }
  697.     else
  698.     {
  699.         fname_expand(&fname, &sfname);
  700.         /*
  701.          * if the file name is already used in another buffer:
  702.          * - if the buffer is loaded, fail
  703.          * - if the buffer is not loaded, delete it from the list
  704.          */
  705.         buf = buflist_findname(fname);
  706.         if (buf != NULL && buf != curbuf)
  707.         {
  708.             if (buf->b_ml.ml_mfp != NULL)        /* it's loaded, fail */
  709.             {
  710.                 if (message)
  711.                     EMSG("Buffer with this name already exists");
  712.                 return FAIL;
  713.             }
  714.             close_buffer(buf, TRUE, TRUE);        /* delete from the list */
  715.         }
  716.         fname = strsave(fname);
  717.         sfname = strsave(sfname);
  718.         if (fname == NULL || sfname == NULL)
  719.         {
  720.             free(sfname);
  721.             free(fname);
  722.             return FAIL;
  723.         }
  724.         free(curbuf->b_filename);
  725.         free(curbuf->b_sfilename);
  726.         curbuf->b_filename = fname;
  727.         curbuf->b_sfilename = sfname;
  728.     }
  729.     if (did_cd)
  730.         curbuf->b_xfilename = curbuf->b_filename;
  731.     else
  732.         curbuf->b_xfilename = curbuf->b_sfilename;
  733.  
  734. #ifndef MSDOS
  735.     curbuf->b_shortname = FALSE;
  736. #endif
  737.     return OK;
  738. }
  739.  
  740. /*
  741.  * set alternate file name for current window
  742.  *
  743.  * used by dowrite() and doecmd()
  744.  */
  745.     void
  746. setaltfname(fname, sfname, lnum)
  747.     char_u        *fname;
  748.     char_u        *sfname;
  749.     linenr_t    lnum;
  750. {
  751.     BUF        *buf;
  752.  
  753.     buf = buflist_new(fname, sfname, lnum, FALSE);
  754.     if (buf != NULL)
  755.         curwin->w_alt_fnum = buf->b_fnum;
  756. }
  757.  
  758. /*
  759.  * add a file name to the buflist and return its number
  760.  *
  761.  * used by qf_init(), main() and doarglist()
  762.  */
  763.     int
  764. buflist_add(fname)
  765.     char_u        *fname;
  766. {
  767.     BUF        *buf;
  768.  
  769.     buf = buflist_new(fname, NULL, (linenr_t)0, FALSE);
  770.     if (buf != NULL)
  771.         return buf->b_fnum;
  772.     return 0;
  773. }
  774.  
  775. /*
  776.  * set alternate lnum for current window
  777.  */
  778.     void
  779. buflist_altlnum()
  780. {
  781.     buflist_setlnum(curbuf, curwin->w_cursor.lnum);
  782. }
  783.  
  784. /*
  785.  * return nonzero if 'fname' is not the same file as current file
  786.  * fname must have a full path (expanded by FullName)
  787.  */
  788.     int
  789. otherfile(fname)
  790.     char_u    *fname;
  791. {                                    /* no name is different */
  792.     if (fname == NULL || *fname == NUL || curbuf->b_filename == NULL)
  793.         return TRUE;
  794.     return fnamecmp(fname, curbuf->b_filename);
  795. }
  796.  
  797.     void
  798. fileinfo(fullname)
  799.     int fullname;
  800. {
  801.     char_u        *name;
  802.  
  803. #if 0        /* this message is quite useless */
  804.     if (bufempty())
  805.     {
  806.         MSG("Buffer Empty");
  807.         return;
  808.     }
  809. #endif
  810.  
  811.     if (curbuf->b_filename == NULL)
  812.         STRCPY(IObuff, "\"No File");
  813.     else
  814.     {
  815.         if (!fullname && curbuf->b_sfilename != NULL)
  816.             name = curbuf->b_sfilename;
  817.         else
  818.             name = curbuf->b_filename;
  819.             /* careful: home_replace cals vimgetenv(), which also uses IObuff! */
  820.         home_replace(name, IObuff + 1, IOSIZE - 1);
  821.         IObuff[0] = '"';
  822.     }
  823.  
  824.     sprintf((char *)IObuff + STRLEN(IObuff),
  825.                         "\"%s%s%s line %ld of %ld --%d%%-- col %d",
  826.             curbuf->b_changed ? " [Modified]" : "",
  827.             curbuf->b_notedited ? " [Not edited]" : "",
  828.             curbuf->b_p_ro ? " [readonly]" : "",
  829.             (long)curwin->w_cursor.lnum,
  830.             (long)curbuf->b_ml.ml_line_count,
  831.             (int)(((long)curwin->w_cursor.lnum * 100L) / (long)curbuf->b_ml.ml_line_count),
  832.             (int)curwin->w_cursor.col + 1);
  833.  
  834.     if (arg_count > 1)
  835.         sprintf((char *)IObuff + STRLEN(IObuff), " (file %d of %d)", curwin->w_arg_idx + 1, arg_count);
  836.     msg(IObuff);
  837. }
  838.  
  839. /*
  840.  * put filename in title bar of window and in icon title
  841.  */
  842.  
  843. static char_u *lasttitle = NULL;
  844. static char_u *lasticon = NULL;
  845.  
  846.     void
  847. maketitle()
  848. {
  849.     char_u        *t;
  850.     char_u        *i;
  851.  
  852.     if (!p_title && !p_icon)
  853.         return;
  854.  
  855.     if (curbuf->b_filename == NULL)
  856.     {
  857.         t = (char_u *)"";
  858.         i = (char_u *)"No File";
  859.     }
  860.     else
  861.     {
  862.         home_replace(curbuf->b_filename, IObuff, IOSIZE);
  863.         if (arg_count > 1)
  864.             sprintf((char *)IObuff + STRLEN(IObuff), " (%d of %d)", curwin->w_arg_idx + 1, arg_count);
  865.         t = IObuff;
  866.         i = gettail(curbuf->b_filename);        /* use filename only for icon */
  867.     }
  868.  
  869.     free(lasttitle);
  870.     if (p_title)
  871.         lasttitle = alloc((unsigned)(STRLEN(t) + 7));
  872.     else
  873.         lasttitle = NULL;
  874.     if (lasttitle != NULL)
  875.         sprintf((char *)lasttitle, "VIM - %s", (char *)t);
  876.  
  877.     free(lasticon);
  878.     if (p_icon)
  879.         lasticon = strsave(i);
  880.     else
  881.         lasticon = NULL;
  882.  
  883.     resettitle();
  884. }
  885.  
  886.     void
  887. resettitle()
  888. {
  889.     mch_settitle(lasttitle, lasticon);
  890. }
  891.  
  892. /*
  893.  * If fname is not a full path, make it a full path
  894.  */
  895.     char_u    *
  896. fix_fname(fname)
  897.     char_u    *fname;
  898. {
  899.     if (fname != NameBuff)            /* if not already expanded */
  900.     {
  901.         if (!isFullName(fname))
  902.         {
  903.             (void)FullName(fname, NameBuff, MAXPATHL);
  904.             fname = NameBuff;
  905.         }
  906. #ifdef AMIGA
  907.         else
  908.         {
  909.             STRNCPY(NameBuff, fname, (size_t)MAXPATHL);    /* make copy so we can change it */
  910.             fname = NameBuff;
  911.             fname_case(fname);            /* set correct case for filename */
  912.         }
  913. #endif
  914.     }
  915.     return fname;
  916. }
  917.  
  918. /*
  919.  * make fname a full file name, set sfname to fname if not NULL
  920.  */
  921.     void
  922. fname_expand(fname, sfname)
  923.     char_u        **fname;
  924.     char_u        **sfname;
  925. {
  926.     if (*fname == NULL)            /* if no file name given, nothing to do */
  927.         return;
  928.     if (*sfname == NULL)        /* if no short file name given, use fname */
  929.         *sfname = *fname;
  930.     *fname = fix_fname(*fname);    /* expand to full path */
  931. }
  932.  
  933. /*
  934.  * do_arg_all: open a window for each argument
  935.  */
  936.     void
  937. do_arg_all()
  938. {
  939.     int        win_count;
  940.     int        i;
  941.  
  942.     if (arg_count <= 1)
  943.     {
  944.         EMSG("Argument list contains less than 2 files");
  945.         return;
  946.     }
  947.     /*
  948.      * 1. close all but first window
  949.      * 2. make the desired number of windows
  950.      * 3. start editing the first window (hide the current window contents)
  951.      * 4. stuff commands to fill the other windows
  952.      */
  953.     close_others(FALSE);
  954.     curwin->w_arg_idx = 0;
  955.     win_count = make_windows(arg_count);
  956.     for (i = 0; i < win_count; ++i)
  957.     {
  958.                                                 /* edit file i */
  959.         (void)doecmd(arg_files[i], NULL, NULL, TRUE, (linenr_t)1);
  960.         curwin->w_arg_idx = i;
  961.         if (curwin->w_next == NULL)                /* just checking */
  962.             break;
  963.         win_enter(curwin->w_next, FALSE);
  964.     }
  965.     win_enter(firstwin, FALSE);                    /* back to first window */
  966. }
  967.  
  968. /*
  969.  * do_arg_all: open a window for each buffer
  970.  *
  971.  * when 'all' is TRUE, also load inactive buffers
  972.  */
  973.     void
  974. do_buffer_all(all)
  975.     int        all;
  976. {
  977.     int        win_count;
  978.     BUF        *buf;
  979.     int        i;
  980.  
  981. /*
  982.  * count number of desired windows
  983.  */
  984.     win_count = 0; 
  985.     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  986.         if (all || buf->b_ml.ml_mfp != NULL)
  987.             ++win_count;
  988.  
  989.     if (win_count == 0)                /* Cannot happen? */
  990.     {
  991.         EMSG("No relevant entries in buffer list");
  992.         return;
  993.     }
  994.  
  995.     /*
  996.      * 1. close all but first window
  997.      * 2. make the desired number of windows
  998.      * 3. stuff commands to fill the windows
  999.      */
  1000.     close_others(FALSE);
  1001.     curwin->w_arg_idx = 0;
  1002.     win_count = make_windows(win_count);
  1003.     buf = firstbuf;
  1004.     for (i = 0; i < win_count; ++i)
  1005.     {
  1006.         for ( ; buf != NULL; buf = buf->b_next)
  1007.             if (all || buf->b_ml.ml_mfp != NULL)
  1008.                 break;
  1009.         if (buf == NULL)            /* Cannot happen? */
  1010.             break;
  1011.         if (i != 0)
  1012.             stuffReadbuff((char_u *)"\n\027\027:");    /* CTRL-W CTRL-W */
  1013.         stuffReadbuff((char_u *)":buf ");            /* edit Nth buffer */
  1014.         stuffnumReadbuff((long)buf->b_fnum);
  1015.         buf = buf->b_next;
  1016.     }
  1017.     stuffReadbuff((char_u *)"\n100\027k");        /* back to first window */
  1018. }
  1019.